(function () {
	/* 
假设我们有这么一个函数，它可以接受多个类型的参数并进行对应处理，比如：

对于字符串，返回部分截取；
对于数字，返回它的 n 倍；
对于对象，修改它的属性并返回。
*/

	//是 any 大法好？
	function handle(input: any): any {}

	//难道要用重载一个个声明可能的关联关系？
	function handle1(input: string): string;
	function handle1(input: number): number;
	function handle1(input: {}): {};

	//还是用联合类型来包括所有可能类型？
	function handle1(input: string | number | {}): string | number | {} {
		return input;
	}

	// 重载可实现 但是，同事觉得你垃圾
	const shouldBeString = handle1('linbudu');
	const shouldBeNumber = handle1(599);
	const shouldBeObject = handle1({ name: 'linbudu' });

	//这个时候，我们就该请出泛型了：
	//#region 类型说明
	// 在基于参数类型进行填充泛型时，其类型信息会被推断到尽可能精确的程度，如这里会推导到字面量类型而不是基础类型。这是因为在直接传入一个值时，这个值是不会再被修改的，因此可以推导到最精确的程度。而如果你使用一个变量作为参数，那么只会使用这个变量标注的类型（在没有标注时，会使用推导出的类型）。
	//#endregion

	const author = 'lys'; // 使用 const 声明，被推导为 "linbudu"
	let authorAge = 18; // 使用 let 声明，被推导为 number
	function handle2<T>(input: T): T; // 重载声明而已（试试水）
	function handle2<T>(input: T): void; // 重载声明而已
	function handle2<T>(input: T): T {
		return input;
	}

	console.log(handle2(author)); // 填充为字面量类型 "linbudu"
	handle2(authorAge); // 填充为基础类型 number

	//再看一个例子：
	function swap<T, U>([start, end]: [T, U]): [U, T] {
		return [end, start];
	}

	const swapped1 = swap(['lys', 599]);
	const swapped2 = swap([null, 599]);
	const swapped3 = swap([{ name: 'lys' }, {}]);

	//函数中的泛型同样存在约束与默认值
	function handle3<T extends string | number>(input: T): T {
		return input;
	}
	//而 swap2 函数，现在我们只想处理数字元组的情况：
	function swap2<T extends number, U extends number>([start, end]: [T, U]): [U, T] {
		return [end, start];
	}

	const object = { a: 1, b: '2', c: 3 };

	// function pick():Object

	function pick<T extends object, U extends keyof T>(object: T, ...props: Array<U>) {}

	function handle4<T>(payload: T): Promise<[T]> {
		return new Promise<[T]>((res, rej) => {
			res([payload]);
		});
	}

	const handle5 = <T>(input: T): T => {
		return input;
	};

	console.log(handle5(5));
	//需要注意的是在 tsx 文件中泛型的尖括号可能会造成报错，编译器无法识别这是一个组件还是一个泛型，此时你可以让它长得更像泛型一些：
	const handle6 = <T extends any>(input: T): T => {
		return input;
	};

	// 需要注意的是，不要为了用泛型而用泛型，
	function handle7<T>(arg: T): void {
		//泛型参数 T 没有被返回值消费，也没有被内部的逻辑消费，这种情况下即使随着调用填充了泛型参数，也是没有意义的。因此这里你就完全可以用 any 来进行类型标注
		console.log(arg);
	}
})();
